import json
from json import JSONDecodeError

from dojo.models import Finding


class OssIndexDevauditParser:

    """
    OssIndex Devaudit Results Parser
    Parses files created by the Sonatype OssIndex Devaudit tool
    https://github.com/sonatype-nexus-community/DevAudit
    """

    def get_scan_types(self):
        return ["OssIndex Devaudit SCA Scan Importer"]

    def get_label_for_scan_types(self, scan_type):
        return scan_type  # no custom label for now

    def get_description_for_scan_types(self, scan_type):
        return "Import OssIndex Devaudit SCA Scan in json format."

    def get_findings(self, json_file, test):
        tree = self.parse_json(json_file)

        if tree:
            return list(self.get_items(tree, test))
        return []

    def parse_json(self, json_file):
        if json_file is None:
            return None
        try:
            tree = json.load(json_file)
        except JSONDecodeError:
            msg = "Invalid format"
            raise ValueError(msg)

        return tree

    def get_items(self, tree, test):
        items = {}

        results = dict(tree.items())
        for package in results.get("Packages", []):
            package_data = package["Package"]
            if len(package.get("Vulnerabilities", [])) > 0:
                for vulnerability in package.get("Vulnerabilities", []):
                    item = get_item(
                        dependency_name=package_data["name"],
                        dependency_version=package_data["version"],
                        dependency_source=package_data["pm"],
                        vulnerability=vulnerability,
                        test=test,
                    )
                    unique_key = vulnerability["id"]
                    items[unique_key] = item

        return items.values()


def get_item(
    dependency_name, dependency_version, dependency_source, vulnerability, test,
):
    cwe_data = vulnerability.get("cwe", "CWE-1035")
    if cwe_data is None or cwe_data.startswith("CWE") is False:
        cwe_data = "CWE-1035"
    try:
        cwe = int(cwe_data.split("-")[1])
    except ValueError:
        msg = "Attempting to convert the CWE value to an integer failed"
        raise ValueError(msg)

    return Finding(
        title=dependency_source
        + ":"
        + dependency_name
        + " - "
        + "("
        + dependency_version
        + ", "
        + cwe_data
        + ")",
        test=test,
        severity=get_severity(vulnerability.get("cvssScore", "")),
        description=vulnerability["title"],
        cwe=cwe,
        cvssv3=vulnerability["cvssVector"].replace("CVSS:3.0", ""),
        mitigation="Upgrade the component to the latest non-vulnerable version, or remove the package if it is not in use.",
        references=vulnerability.get("reference", ""),
        false_p=False,
        duplicate=False,
        out_of_scope=False,
        mitigated=None,
        static_finding=False,
        dynamic_finding=False,
        impact="No impact provided by scan",
    )


def get_severity(cvss_score):
    result = "Info"

    if cvss_score:
        ratings = [
            ("Critical", 9.0, 10.0),
            ("High", 7.0, 8.9),
            ("Medium", 4.0, 6.9),
            ("Low", 0.1, 3.9),
        ]

        for severity, low, high in ratings:
            if low <= float(cvss_score) <= high:
                result = severity

    return result
